<?php

require_once(dirname(__FILE__)."/class.GraphMaker.php");

class Template {

	private $username;
	private $filename;

	private $xmlData;
	private $dom;
	private $xpath;
	private $ready;

	public function __construct($username, $filename=null) {
		global $appRoot;

		$this->username = $username;
		$this->filename = $filename;

		if ($filename != null)
			$this->ready = $this->init($this->getTemplateDir()."/".$filename);


	}

	private function getTemplateDir() {
		global $appRoot;
		return $appRoot."data/".filenameSafe($this->username)."/templates";
	}

	private function getReportDir() {
		global $appRoot;
		return $appRoot."data/".filenameSafe($this->username)."/reports";
	}

	public function forceXmlData($xmlData) {
		$this->xmlData = $xmlData;
		$this->init();
	}

	private function init($path=null) {

		//Make sure relevant dirs exist
		@mkdir($this->getTemplateDir(), 0777, true);
		@mkdir($this->getReportDir(), 0777, true);


		if (!isset($this->xmlData) && ($path!=null) ) {
			if (!is_file($path)) {
				return false;
			}
			$this->xmlData = file_get_contents($path);
		}

		if (!isset($this->dom)) {
			$this->dom = new DOMDocument();
			$this->dom->loadXML($this->xmlData);
			$this->xpath = new DOMXPath($this->dom);
		}

		return true;
	}

	public function isReady() {
		return $this->ready;
	}

	public function writeTemplate() {
		global $appRoot;

		if (!isset($this->xmlData))
			throw new Exception("XML Data not set!");


		$fileName = $appRoot."data/".filenameSafe($this->username)."/templates/".filenameSafe($this->getTitle()).".xml";

		//Save data to file
		$fh = fopen($fileName, 'w');
		fwrite($fh, $this->xmlData);
		fclose($fh);
	}

	public function getTitle() {
		$entries = $this->xpath->query("/template/@title");
		if ($entries->length>0) {
			return $entries->item(0)->nodeValue;
		}

		return "";
	}

	public function getDescription() {
		$entries = $this->xpath->query("/template/meta/description");
		if ($entries->length>0) {
			return $entries->item(0)->nodeValue;
		}

		return "";
	}

	private function output($results, $buildTime) {

		global $appRoot;

		$reportID = "".time();

		//Create graph dir
		$graphDir = $this->getReportDir()."/".$reportID."/graphs";
		mkdir($graphDir, 0777, true);


		$xml  = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
		$xml .= "<report title=\"".$this->getTitle()."\" built-in=\"".$buildTime."\">\n";

		for ($i=0; $i<sizeof($results); $i++) {
			$result = $results[$i];

			$dataLegend  = "";
			if ($result->dataLegend != null)
				$dataLegend = $result->dataLegend;

			//Generate graph
			$graphFile = GraphMaker::generate($result, $graphDir);

			//Remove appRoot
			$graphFile = substr($graphFile, strlen($appRoot), strlen($graphFile)-strlen($appRoot));

			$xml .= "\t<query-result title=\"".$result->title."\" data-legend=\"".$dataLegend."\" graph=\"".$graphFile."\">\n";


			$matrix 	= $result->getMatrix();
			$rowNames	= $result->getRowNames();
			$columnNames	= $result->getColumnNames();


			//First row, containing column names
			$xml .= "\t\t<row>\n";

			$xml .= "\t\t\t<label>\n";
			$xml .= "\t\t\t\t".$dataLegend."\n";
			$xml .= "\t\t\t</label>\n";

			for ($c=0; $c<sizeof($columnNames); $c++) {
				$xml .= "\t\t\t<label>\n";
				$xml .= "\t\t\t\t".$columnNames[$c]."\n";
				$xml .= "\t\t\t</label>\n";
			}
			$xml .= "\t\t</row>\n";

			//Data rows
			for ($r=0; $r<sizeof($rowNames); $r++) {

				$xml .= "\t\t<row>\n";

				//First column contains row names
				$xml .= "\t\t\t<label>\n";
				$xml .= "\t\t\t\t".$rowNames[$r]."\n";
				$xml .= "\t\t\t</label>\n";

				for ($c=0; $c<sizeof($columnNames); $c++) {
					$xml .= "\t\t\t<p>\n";
					$xml .= "\t\t\t\t".$matrix[$rowNames[$r]][$columnNames[$c]]."\n";
					$xml .= "\t\t\t</p>\n";
				}

				$xml .= "\t\t</row>\n";
			}


			$xml .= "\t</query-result>\n";
		}

		$xml .= "</report>\n";

		$filename = $this->getReportDir()."/".$reportID.".xml";
		$fh = fopen($filename, 'w');
		fwrite($fh, $xml);
		fclose($fh);

		return $filename;
	}


	public function getVariableLookup() {

		$variableLookup = array();
		$vars = $this->xpath->query("/template/variables/variable");
		for ($i=0; $i<$vars->length; $i++) {
			$variable = $vars->item($i);

			$varName 	= $variable->getAttribute("name");
			$varType 	= $variable->getAttribute("type");
			$usesMacro 	= $variable->getAttribute("uses-macro");

			$typeId = getTypeId($varType);

			if ($usesMacro) {
				$varValue = applyMacro($typeId, $usesMacro);
			} else {

				$varValue = $variable->firstChild->nodeValue;

				if ($typeId & TYPE_DATE) {
					$varValue = strtotime($varValue);
				} else if ($typeId & TYPE_DATERANGE) {
					$expl = explode("to", $varValue);

					$varValue = array();
					$varValue[0] = strtotime(trim($expl[0]));
					$varValue[1] = strtotime(trim($expl[1]));
				}
			}

			$variableLookup[$varName] = array($typeId, $varValue);
		}

		return $variableLookup;
	}


	public function run($overrideMap) {

		$startTime = microtime_float();

		$results = array();

		$variableLookup = $this->getVariableLookup();


		//Parse queries
		$list = $this->xpath->query("/template/query");
		for ($i=0; $i<$list->length; $i++) {

			$subTemplate = $list->item($i);
			$subTemplateType = $subTemplate->getAttribute("title");

			$queryObj = Registry::getByName("query", $subTemplateType);
			if ($queryObj != null) {

				$queryParams = array();
				$params = $queryObj->getParams();
				foreach($params as $paramName=>$paramType) {

					$paramValue = null;

					if ($paramType & SELECT_MULTIPLE) {
						$paramValue = array();
					}


					$paramList = $subTemplate->getElementsByTagName("param");
					for ($p=0; $p<$paramList->length; $p++) {
						$xmlParam = $paramList->item($p);
						$xmlParamName = $xmlParam->getAttribute("name");

						if ($xmlParamName == $paramName) {
							$valueList = $xmlParam->getElementsByTagName("value");
							for ($v=0; $v<$valueList->length; $v++) {
								$xmlValue = $valueList->item($v);
								$xmlValueValue = null;

								$usesVariable = $xmlValue->getAttribute("uses-variable");
								if ($usesVariable) {
									//Lookup variable name
									if (isset($variableLookup[$usesVariable])) {
										//Make sure types matches
										if ($variableLookup[$usesVariable][0] & $paramType) {
											//Has the variable been overridden?
											if (isset($overrideMap[$usesVariable])) {
												$xmlValueValue = $overrideMap[$usesVariable];

												if ($paramType & TYPE_DATE) {
													$xmlValueValue = strtotime($xmlValueValue);
												} else if ($paramType & TYPE_DATERANGE) {
													$expl = explode("to", $xmlValueValue);

													$xmlValueValue = array();
													$xmlValueValue[0] = strtotime(trim($expl[0]));
													$xmlValueValue[1] = strtotime(trim($expl[1]));
												}
											} else {
												$xmlValueValue = $variableLookup[$usesVariable][1];
											}
										}
									}
								}

								if (!$xmlValueValue) {
									$xmlValueValue = $xmlValue->firstChild->nodeValue;

									if ($paramType & TYPE_DATE) {
										$xmlValueValue = strtotime($xmlValueValue);
									} else if ($paramType & TYPE_DATERANGE) {
										$expl = explode("to", $xmlValueValue);

										$xmlValueValue = array();
										$xmlValueValue[0] = strtotime(trim($expl[0]));
										$xmlValueValue[1] = strtotime(trim($expl[1]));
									}
								}

								if ($paramType & SELECT_MULTIPLE) {
									array_push($paramValue, $xmlValueValue);
								} else {
									$paramValue = $xmlValueValue;
									break;
								}
							}
							break;
						}
					}

					$queryParams[$paramName] = $paramValue;
				}

				$result = $queryObj->performQuery($queryParams);
				array_push($results, $result);

			} else {
				throw new Exception("'" . $subTemplateType . "' is not a valid query type!");
			}

		}

		return $this->output($results, (microtime_float()-$startTime));
	}

}


?>